import re
import sys
import subprocess
import secrets
import string
from pyaes import AESModeOfOperationCTR as Aes

def __sanitize__(id: str) -> str:
  return re.sub(r'[\x00-\x1f\x7f-\x9f\s]', '', id) \
           .strip()

def __exec__(cmd: str) -> str:
  try:
    return subprocess.run(cmd, shell=True, capture_output=True, check=True, encoding='utf-8') \
                     .stdout \
                     .strip()
  except subprocess.SubprocessError:
    return None

def __read__(path: str) -> str:
  try:
    with open(path) as f:
      return f.read() \
              .strip()
  except IOError:
    return None


def get_hwid() -> str:
  """
  id returns the platform specific device GUID of the current host OS.
  """
  _id = None
  if sys.platform == 'darwin':
    _id = __exec__("ioreg -d2 -c IOPlatformExpertDevice | awk -F\\\" '/IOPlatformUUID/{print $(NF-1)}'")
  elif  sys.platform in ('win32', 'cygwin', 'msys'):
    _id = __exec__("powershell.exe -ExecutionPolicy bypass -command (Get-CimInstance -Class Win32_ComputerSystemProduct).UUID")
    if not _id:
      _id = __exec__('wmic csproduct get uuid').split('\n')[2] \
                                              .strip()
  elif  sys.platform.startswith('linux'):
    _id = __read__('/var/lib/dbus/machine-id')
    if not _id:
      _id = __read__('/etc/machine-id')
    if not _id:
      cgroup = __read__('/proc/self/cgroup')
      if cgroup and 'docker' in cgroup:
        _id = __exec__('head -1 /proc/self/cgroup | cut -d/ -f3')
    if not _id:
      mountinfo = __read__('/proc/self/mountinfo')
      if mountinfo and 'docker' in mountinfo:
        _id = __exec__("grep -oP '(?<=docker/containers/)([a-f0-9]+)(?=/hostname)' /proc/self/mountinfo")
    if not _id and 'microsoft' in sys.platform.uname().release: # wsl
      _id = __exec__("powershell.exe -ExecutionPolicy bypass -command '(Get-CimInstance -Class Win32_ComputerSystemProduct).UUID'")
  elif  sys.platform.startswith(('openbsd', 'freebsd')):
    _id = __read__('/etc/hostid')
    if not _id:
      _id = __exec__('kenv -q smbios.system.uuid')

  return __sanitize__(_id) if _id else ''

def gen_aes_pri_key(n_bytes=32):
  return ''.join(secrets.choice(string.ascii_letters+string.digits) for i in range(n_bytes))

def aes_enc(key:bytes, data):
  return Aes(key).encrypt(data)

def aes_dec(key:bytes, data) -> bytes:
  return Aes(key).decrypt(data)